package cn.thoughtworks.school.pactise.diary.adapters.inbound.rest.resources.practiseDiary;


import cn.thoughtworks.school.pactise.diary.adapters.inbound.rest.auth.annotation.Auth;
import cn.thoughtworks.school.pactise.diary.adapters.inbound.rest.auth.configrations.AuthResolver;
import cn.thoughtworks.school.pactise.diary.adapters.inbound.rest.resources.comment.CommentDto;
import cn.thoughtworks.school.pactise.diary.application.gateway.user.UserDto;
import cn.thoughtworks.school.pactise.diary.application.gateway.user.UserService;
import cn.thoughtworks.school.pactise.diary.application.usecases.comment.QueryCommentUseCase;
import cn.thoughtworks.school.pactise.diary.application.usecases.practiseDiary.EditExcellentDiaryUseCase;
import cn.thoughtworks.school.pactise.diary.application.usecases.practiseDiary.QueryExcellentDiaryUseCase;
import cn.thoughtworks.school.pactise.diary.application.usecases.practiseDiary.QueryPractiseDiaryUseCase;
import cn.thoughtworks.school.pactise.diary.domain.context.practiseDiaryContext.comment.Comment;
import cn.thoughtworks.school.pactise.diary.domain.context.practiseDiaryContext.practiseDiary.ExcellentDiary;
import cn.thoughtworks.school.pactise.diary.domain.context.practiseDiaryContext.practiseDiary.PractiseDiary;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@RestController
@RequestMapping(value = "/api/excellentDiaries")
public class ExcellentDiaryResource {
    private final QueryExcellentDiaryUseCase queryExcellentDiaryUseCase;
    private final EditExcellentDiaryUseCase editExcellentDiaryUseCase;
    private final QueryPractiseDiaryUseCase queryPractiseDiaryUseCase;
    private final QueryCommentUseCase queryCommentUseCase;
    private final UserService userService;

    public ExcellentDiaryResource(QueryExcellentDiaryUseCase queryExcellentDiaryUseCase, EditExcellentDiaryUseCase editExcellentDiaryUseCase, QueryPractiseDiaryUseCase queryPractiseDiaryUseCase, QueryCommentUseCase queryCommentUseCase, UserService userService) {
        this.queryExcellentDiaryUseCase = queryExcellentDiaryUseCase;
        this.editExcellentDiaryUseCase = editExcellentDiaryUseCase;
        this.queryPractiseDiaryUseCase = queryPractiseDiaryUseCase;
        this.queryCommentUseCase = queryCommentUseCase;
        this.userService = userService;
    }


    @RequestMapping(value = "", method = RequestMethod.POST)
    public ResponseEntity<ExcellentDiaryCreateDto> createExcellentDiary(@Auth AuthResolver.User user, @RequestBody ExcellentDiaryRequest excellentDiaryRequest) {

        ExcellentDiary existDiary = queryExcellentDiaryUseCase.findByDiaryId(excellentDiaryRequest.getDiaryId());
        if (existDiary != null) {
            return new ResponseEntity<>(HttpStatus.CONFLICT);
        }
        Date now = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        excellentDiaryRequest.setOperatorId(user.getId());
        excellentDiaryRequest.setCreateTime(simpleDateFormat.format(now));
        ExcellentDiary excellentDiary = editExcellentDiaryUseCase.save(excellentDiaryRequest.toDomain());
        String uri = "/api/users/" + user.getId() + "/excellentDiaries/" + excellentDiary.getId();
        return new ResponseEntity<>(new ExcellentDiaryCreateDto(uri), HttpStatus.CREATED);
    }

    @RequestMapping(value = "/{excellentDiaryId}", method = RequestMethod.DELETE)
    public ResponseEntity deleteExcellentDiary(@PathVariable Long excellentDiaryId) {
        ExcellentDiary existDiary = queryExcellentDiaryUseCase.findByDiaryId(excellentDiaryId);
        if (existDiary == null) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
        editExcellentDiaryUseCase.deleteById(existDiary.getId());
        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }

    @RequestMapping(value = "", method = RequestMethod.GET)
    public ResponseEntity<ExcellentDiariesDto> getAllExcellentDiaries(@RequestParam(value = "page", defaultValue = "1") int page, @RequestParam(value = "pageSize", defaultValue = "20") Integer size) {
        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        Pageable pageable = new PageRequest(page - 1, size, sort);

        Page<ExcellentDiary> excellentDiaryPage = queryExcellentDiaryUseCase.findAll(pageable);
        List<Long> diaryIds = excellentDiaryPage.getContent().stream().map(ExcellentDiary::getDiaryId).collect(Collectors.toList());
        List<PractiseDiary> excellentDiaries = queryPractiseDiaryUseCase.findAllByIdIn(diaryIds);
        List<PractiseDiary> excellentDiariesSort = sortExcellentDiaries(diaryIds, excellentDiaries);
        List<Long> userIds = excellentDiariesSort.stream().map(PractiseDiary::getAuthorId).collect(Collectors.toList());
        List<UserDto> users = userService.getUsersByIds(userIds);

        List<ExcellentPractiseDiaryDto> excellentDiariesAndComments = new ArrayList();
        excellentDiariesSort.forEach(diary -> {
            List<Comment> comments = queryCommentUseCase.findByPractiseDiaryId(diary.getId());

            UserDto diaryAuthorInfo = users.stream().filter(item ->
                Objects.equals(item.getId(), diary.getAuthorId()))
                .findFirst()
                .orElse(new UserDto());

            List<CommentDto> commentsInfo = queryCommentUseCase.getCommonInfo(comments);

            excellentDiariesAndComments.add(new ExcellentPractiseDiaryDto(diary, commentsInfo, diaryAuthorInfo));
        });


        int total = queryExcellentDiaryUseCase.findAll().size();
        return new ResponseEntity<>(new ExcellentDiariesDto(total, excellentDiariesAndComments), HttpStatus.OK);
    }

    private List<PractiseDiary> sortExcellentDiaries(List<Long> diaryIds, List<PractiseDiary> excellentDiaries) {
        List<PractiseDiary> excellentDiariesSort = new ArrayList<>();
        for (Long id : diaryIds) {
            for (PractiseDiary practiseDiary : excellentDiaries) {
                if (practiseDiary.getId().equals(id)) {
                    excellentDiariesSort.add(practiseDiary);
                }
            }
        }
        return excellentDiariesSort;
    }
}
